package svc

import (
	"crypto/x509"
	"fmt"
	"laundry-service/app/client/internal/buffer"
	"laundry-service/app/client/internal/config"
	"laundry-service/app/client/internal/repo"
	"log"
	"time"

	"github.com/go-redis/redis/v8"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"github.com/silenceper/wechat/v2"

	"github.com/silenceper/wechat/v2/cache"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"

	miniprogram2 "github.com/silenceper/wechat/v2/miniprogram"
	miniConfig "github.com/silenceper/wechat/v2/miniprogram/config"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	wxutils "github.com/wechatpay-apiv3/wechatpay-go/utils"
)

type ServiceContext struct {
	Config       config.Config
	Db           repo.IUserDao
	MiniProgram  *miniprogram2.MiniProgram
	Opt          []core.ClientOption
	ProductCache *buffer.ProductCache
	RedisClient  *redis.Client
}

func initRedis(c *config.Config) *redis.Client {
	return redis.NewClient(&redis.Options{
		Addr:     c.RDS.Addr,
		Password: c.RDS.Password,
		DB:       c.RDS.DB,
	})
}

func initDatasource(c *config.Config) *gorm.DB {
	dsn := c.DB.DataSource
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatal(err)
	}

	sqlDB, err := db.DB()
	if err != nil {
		log.Fatal(err)
	}
	sqlDB.SetMaxIdleConns(c.DB.MaxIdleConns)
	sqlDB.SetMaxOpenConns(c.DB.MaxOpenConns)
	sqlDB.SetConnMaxLifetime(time.Second * time.Duration(c.DB.ConnMaxLifetime))

	return db
}

func initWxMiniProgram(c *config.Config) *miniprogram2.MiniProgram {
	wc := wechat.NewWechat()
	memory := cache.NewMemory()
	cfg := &miniConfig.Config{
		AppID:     c.WX.AppID,
		AppSecret: c.WX.AppSecret,
		Cache:     memory,
	}
	return wc.GetMiniProgram(cfg)
}

func initWxPaymentOpts(c *config.Config) []core.ClientOption {
	privateKey, err := wxutils.LoadPrivateKeyWithPath(c.WxPay.PrivateKeyPath)
	if err != nil {
		fmt.Printf("load private err:%s", err.Error())
		log.Fatal(err)
	}

	wechatPayCertificate, err := wxutils.LoadCertificateWithPath(c.WxPay.WechatCertificatePath)
	if err != nil {
		fmt.Printf("load certificate err:%s", err)
		log.Fatal(err)
	}

	return []core.ClientOption{
		option.WithMerchantCredential(c.WxPay.MchID, c.WxPay.MchCertSerialNumber, privateKey), // 设置商户相关配置
		option.WithWechatPayCertificate([]*x509.Certificate{wechatPayCertificate}),            // 设置微信支付平台证书，用于校验回包信息用
		option.WithoutValidator(), //跳过证书的效验
	}
}

func NewServiceContext(c config.Config) *ServiceContext {
	redisClient := initRedis(&c)
	return &ServiceContext{
		Config:       c,
		Db:           repo.NewUserDao(initDatasource(&c)),
		MiniProgram:  initWxMiniProgram(&c),
		Opt:          initWxPaymentOpts(&c),
		RedisClient:  redisClient,
		ProductCache: buffer.NewProductCache(redisClient),
	}
}
